#ifndef __MY_DATA__
#define __MY_DATA__
#include"util.hpp"
#include<mutex>
#include<mysql/mysql.h>
#include<cstdlib>
using namespace std;

namespace aod{
    #define HOST "127.0.0.1"
    #define USER "root"
    #define PASS ""
    #define NAME "aod_system"
    //对数据库接口进行封装方便使用
    static MYSQL *MysqlInit()//数据库初始化
    {
        MYSQL* mysql = mysql_init(NULL);//操作句柄初始化
        if(mysql==NULL)
        {
            cout<<"init mysql instance failed!\n";
            return NULL;
        }
        if(mysql_real_connect(mysql,HOST,USER,PASS,NAME,0,NULL,0)==NULL)//连接服务器
        {
            cout<<"connect server failed!\n";
            mysql_close(mysql);
            return NULL;
        }
        mysql_set_character_set(mysql,"utf8");//设置客户端字符集
        return mysql;
    }
    static void MysqlDestroy(MYSQL *mysql)//数据库销毁
    {
        if(mysql!= NULL)
        {
            mysql_close(mysql);
        }
        return;
    }
    static bool MysqlQuery(MYSQL *mysql, const std::string &sql)//语句执行
    {
        int ret = mysql_query(mysql,sql.c_str());//执行sql语句
        if(ret!=0)
        {
            cout<<sql<<endl;
            cout<<mysql_error(mysql)<<endl;
            return false;
        }
        return true;
    }
    class TableVideo{
        private:
            MYSQL* _mysql;//一个对象就是一个客户端，管理一张表
            std::mutex _mutex;//防备操作对象在多线程中使用存在的线程安全问题
        public:
            TableVideo()//操作句柄初始化
            {
                _mysql = MysqlInit();
                if(_mysql==NULL)
                {
                    exit(-1);
                }
            }
            ~TableVideo()//释放mydql操作句柄
            {
                MysqlDestroy(_mysql);
            }
            bool Insert(const Json::Value &video)//新增-传入视频信息
            {
                string sql;
                sql.resize(4096+video["info"].asString().size());//防止info信息过长
                #define INSERT_VIDEO "insert tb_video values(null,'%s','%s','%s','%s');"
                if (video["name"].asString().size() == 0) {
					return false;
				}
                //要完成的细致的话需要对各个数据进行校验，因为不校验直接用就有可能出问题
                sprintf(&sql[0],INSERT_VIDEO,video["name"].asCString(),
                        video["info"].asCString(),
                        video["video"].asCString(),
                        video["image"].asCString());
                return MysqlQuery(_mysql,sql);
            }
            bool Update( int video_id,const Json::Value &video)//修改-传入视频id,输出视频信息
            {
                string sql;
                sql.resize(4096+video["info"].asString().size());//防止info信息过长
                #define UPDATE_VIDEO "update tb_video set name='%s',info='%s' where id=%d;"
                sprintf(&sql[0],UPDATE_VIDEO,video["name"].asCString(),
                        video["info"].asCString(),video_id);
                return MysqlQuery(_mysql,sql);
            }
            bool Delete(int video_id)//删除-传入视频id
            {
                #define DELETE_VIDEO "delete from tb_video where id = %d;"
                char sql[1024]={0};
                sprintf(sql,DELETE_VIDEO,video_id);
                return MysqlQuery(_mysql,sql);
            }
            bool SelectAll(Json::Value *videos)//查询-输出所有视频信息
            {
                #define SELECTALL_VIDEO "select * from tb_video;"
                _mutex.lock();//加锁，防止一个线程在执行查看还没有保存另一个线程也在查看无法保存
                bool ret = MysqlQuery(_mysql,SELECTALL_VIDEO);
                if(ret==false)
                {
                    _mutex.unlock();
                    return false;
                }
                MYSQL_RES *res = mysql_store_result(_mysql);//保存查询结果到本地
                if(res==NULL)
                {
                    cout<<"mysql store result failed!\n";
                    _mutex.unlock();
                    return false;
                }
                _mutex.unlock();
                int row_num = mysql_num_rows(res);//获取行数
                for(int i=0;i<row_num;i++)
                {
                    MYSQL_ROW row = mysql_fetch_row(res);//遍历结果
                    Json::Value video;
                    video["id"]=atoi(row[0]);//结果放到video中
                    video["name"]=row[1];
                    video["info"]=row[2];
                    video["video"]=row[3];
                    video["image"]=row[4];
                    videos->append(video);
                }
                mysql_free_result(res);//释放结果集
                return true;
            }
            bool SelectOne(int video_id,Json::Value *video)//查询单个-输入id,输出视频信息
            {
                #define SELECTONE_VIDEO "select * from tb_video where id = %d;"
                char sql[1024]={0};
                sprintf(sql,SELECTONE_VIDEO,video_id);
                _mutex.lock();//加锁，防止一个线程在执行查看还没有保存另一个线程也在查看无法保存
                bool ret = MysqlQuery(_mysql,sql);
                if(ret==false)
                {
                    _mutex.unlock();
                    return false;
                }
                MYSQL_RES *res = mysql_store_result(_mysql);//保存查询结果到本地
                if(res==NULL)
                {
                    cout<<"store result failed!\n";
                    _mutex.unlock();
                    return false;
                }
                _mutex.unlock();
                int row_num = mysql_num_rows(res);//获取行数
                if(row_num!=1)
                {
                    cout<<"have no data!\n";
                    mysql_free_result(res);//释放结果集
                    return false;
                }
                MYSQL_ROW row = mysql_fetch_row(res);//遍历结果
                (*video)["id"]=video_id;//结果放到video中
                (*video)["name"]=row[1];
                (*video)["info"]=row[2];
                (*video)["video"]=row[3];
                (*video)["image"]=row[4];
                mysql_free_result(res);//释放结果集
                return true;
            }
            bool SelectLike(const std::string &key, Json::Value *videos)//模糊匹配-输入关键信息，输出视频信息
            {
                #define SELECTLIKE_VIDEO "select * from tb_video where name like '%%%s%%';"//相当于%s%
                char sql[1024]={0};
                sprintf(sql,SELECTONE_VIDEO,key.c_str());
                _mutex.lock();//加锁，防止一个线程在执行查看还没有保存另一个线程也在查看无法保存

                bool ret = MysqlQuery(_mysql,sql);
                if(ret==false)
                {
                    _mutex.unlock();
                    return false;
                }
                MYSQL_RES *res = mysql_store_result(_mysql);//保存查询结果到本地
                if(res==NULL)
                {
                    cout<<"store result failed!\n";
                    _mutex.unlock();
                    return false;
                }
                _mutex.unlock();
                int row_num = mysql_num_rows(res);//获取行数
                for(int i=0;i<row_num;i++)
                {
                    MYSQL_ROW row = mysql_fetch_row(res);//遍历结果
                    Json::Value video;
                    video["id"]=atoi(row[0]);//结果放到video中
                    video["name"]=row[1];
                    video["info"]=row[2];
                    video["video"]=row[3];
                    video["image"]=row[4];
                    videos->append(video);
                }
                mysql_free_result(res);//释放结果集
                return true;
            }
    };
}

#endif